package com.chenxin.wms.process.stock.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.chenxin.common.annotation.WmsLogs;
import com.chenxin.common.core.domain.AjaxResult;
import com.chenxin.common.core.domain.ProcResult;
import com.chenxin.common.enums.*;
import com.chenxin.common.exception.ServiceException;
import com.chenxin.common.utils.StringUtils;
import com.chenxin.wms.domain.*;
import com.chenxin.wms.domain.dto.BatchForbidRequestDTO;
import com.chenxin.wms.domain.dto.TaskRequestDTO;
import com.chenxin.wms.domain.po.StockMoveInfo;
import com.chenxin.wms.mapper.*;
import com.chenxin.wms.process.stock.IStockProcess;
import com.chenxin.wms.service.ILocationService;
import com.chenxin.wms.service.IObMasterService;
import com.chenxin.wms.service.IWcsTaskService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;

@Service
@Slf4j
public class StockProcessImpl implements IStockProcess {
    @Autowired
    private StockMapper stockMapper;
    @Autowired
    private TaskMapper taskMapper;
    @Autowired
    private LocationMapper locationMapper;
    @Autowired
    private WcsTaskMapper wcsTaskMapper;
    @Autowired
    private WarehouseMapper warehouseMapper;
    @Autowired
    private ContainerMapper contMapper;
    @Autowired
    private StationMapper stationMapper;
    @Autowired
    private ObDetailMapper obDetailMapper;
    @Autowired
    private IObMasterService obMasterService;
    @Autowired
    private ILocationService locationService;
    @Autowired
    private SpuMapper spuMapper;

    @Override
    public ProcResult procWmsStockInsert(StockEntity stockEntity) {
        // 1.对库存信息进行简单判断
        String contNo = stockEntity.getContNo();
        String spuNo = stockEntity.getSpuNo();
        String locationNo = stockEntity.getLocationNo();
        BigDecimal stockQty = stockEntity.getStockQty();
        if (StringUtils.isBlank(contNo)) {
            return ProcResult.error("stock_insert_err#001", "库存【容器编号】不能为空");
        }
        if (StringUtils.isBlank(spuNo)) {
            return ProcResult.error("stock_insert_err#002", "库存【物料编号】不能为空");
        }
        if (StringUtils.isBlank(locationNo)) {
            return ProcResult.error("stock_insert_err#003", "库存【所在位置】不能为空");
        }
        //库存数量必须大于0
        if (stockQty.compareTo(BigDecimal.ZERO) <= 0) {
            return ProcResult.error("stock_insert_err#004", "库存【库存数量】必须大于【0】");
        }
        int rows = stockMapper.insert(stockEntity);
        if (rows == 0) {
            return ProcResult.error("stock_insert_err#005", "库存写入失败！");
        }
        return ProcResult.success("成功写入库存【" + stockEntity.getStockId() + "】");
    }

    @Override
    public ProcResult procWmsStockCheck(String spuNo, BigDecimal reqQty) {
        // 物料编号不能为空
        if (StringUtils.isBlank(spuNo)) {
            return ProcResult.error("stock_check_err#001", "库存【物料编号】不能为空");
        }
        // 获取库内可用数量
        BigDecimal usableStock = stockMapper.getUsableStockBySpuNo(spuNo);
        if (usableStock == null) {
            return ProcResult.error("stock_check_err#003", "物料【" + spuNo + "】无可用库存");
        }
        if (usableStock.compareTo(reqQty) < 0) {
            return ProcResult.error("stock_check_err#002", "物料【" + spuNo + "】库存不足，需求数量【" + reqQty + "】，可用数量【" + usableStock + "】");
        }
        return ProcResult.success("【" + spuNo + "】库存充足，需求数量【" + reqQty + "】");
    }

    @Override
    public ProcResult procWmsStockAllocate(String spuNo, BigDecimal reqQty) {
        return null;
    }

    @Override
    public void procWmsStockMove(StockMoveInfo info) {
        // 0.对输出信息赋初值
        info.setCode("0");
        // 1.对入参信息进行简单判断
        Long taskId = info.getTaskId();
        String fromContNo = info.getFromContNo();
        String toContNo = info.getToContNo();
        Long userId = info.getCreator();
        // 移动类型：01-上架 02-下架 03-出库确认
        String moveType = info.getMoveType();
        if (StringUtils.isNull(taskId)) {
            info.setCode("stock_move_err#001");
            info.setMessage("库存转移失败！【任务ID】不能为空");
            return;
        }
        // 根据任务ID获取相关信息
        TaskEntity taskEntity = taskMapper.selectById(taskId);
        if (taskEntity == null) {
            info.setCode("stock_move_err#002");
            info.setMessage("库存转移失败！【任务ID】对应的任务不存在");
            return;
        }
        // 获取库存相关信息
        Long stockId = taskEntity.getStockId();
        // 将库存ID写入出参，后续若生成新库存则替换即可
        info.setStockId(stockId);
        String toPosition = taskEntity.getToPosition();

        StockEntity stockEntity = stockMapper.selectById(stockId);
        // 根据不同移动类型执行相关业务逻辑
        if (WmsMoveType.UP.getCode().equals(moveType)) {
            // 上架-更新库存信息(位置为货位)
            stockEntity.setLocationNo(toPosition);
            stockEntity.setUpdater(userId);
            stockEntity.setUpdateDate(new Date());
        } else if (WmsMoveType.DOWN.getCode().equals(moveType)) {
            // 下架-位置为出库暂存区（需要获取）
        } else {
            info.setCode("stock_move_err#003");
            info.setMessage("库存转移失败！无法处理移动类型【" + moveType + "】");
            return;
        }
        // 更新库存信息
        int rows = stockMapper.updateById(stockEntity);
        if (rows == 0) {
            info.setCode("stock_move_err#004");
            info.setMessage("库存转移失败！库存【" + stockId + "】更新失败");
            return;
        }
        info.setMessage("库存【" + stockId + "】转移成功！");
    }

    /**
     * 根据容器号查询该容器的所有库存
     *
     * @param contNo 容器编号
     * @return 库存列表
     */
    @Override
    public List<StockEntity> getStocksByContNo(String contNo) {
        QueryWrapper<StockEntity> stockQuery = new QueryWrapper<>();
        stockQuery.lambda().eq(StockEntity::getContNo, contNo);

        return stockMapper.selectList(stockQuery);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void stockDisables(BatchForbidRequestDTO request) {
        List<Long> ids = request.getIds(); // 获取前端传递的 ID 集合
        Long userId = request.getUserId();
        int status = request.getStatus();
        String lockReason = request.getLockReason();
        if (ids == null || ids.isEmpty()) {
            throw new ServiceException("ID 集合不能为空");
        }

        for (Long stockId : ids) {
            StockEntity stockEntity = stockMapper.selectById(stockId);
            if (ObjectUtils.isEmpty(stockEntity)) {
                throw new ServiceException("库存不存在");
            }
            /*
             * 2.虚拟货位上的库存，不允许冻结。
             * 3.非【空闲】状态的库存不允许冻结。
             * 4.存在执行中任务的库存不允许冻结。
             * 5.【冻结】状态的库存，不允许再次【冻结】。
             * 6.【正常】状态的库存，不允许【解冻】操作。
             * 7.【超库龄期】/【超保质期】的库存，不允许解冻操作。
             */
            QueryWrapper<LocationEntity> locationWrapper = new QueryWrapper<>();
            locationWrapper.eq("location_no", stockEntity.getLocationNo());
            LocationEntity locationEntity = locationMapper.selectOne(locationWrapper);
            if (locationEntity.getLocationType().equals("0")) {
                throw new ServiceException("虚拟货位上的库存，不允许冻结");
            }

            if (stockEntity.getStockStatus() > 0) {
                throw new ServiceException("非【空闲】状态的库存不允许冻结");
            }

            QueryWrapper<TaskEntity> taskWrapper = new QueryWrapper<>();
            taskWrapper.eq("from_cont_no", stockEntity.getContNo())
                    .eq("task_status", "1");
            Long count = taskMapper.selectCount(taskWrapper);
            if (count > 0) {
                throw new ServiceException("存在执行中任务的库存，不允许冻结");
            }

            //前端传入status 1就是冻结库存，传入 0就是解冻库存
            int activeNew;
            if (status == 1) {
                if (stockEntity.getLockStatus() == 1) {
                    throw new ServiceException("【冻结】状态的库存，不允许再次【冻结】");
                }
                activeNew = 1;
                stockEntity.setLockReason(lockReason);
            } else {
                if (stockEntity.getLockStatus() == 0) {
                    throw new ServiceException("【正常】状态的库存，不允许【解冻】操作");
                }
                if (stockEntity.getLockStatus() == 2) {
                    throw new ServiceException("【超保质期】的库存，不允许解冻操作");
                }
                activeNew = 0;
                stockEntity.setLockReason("");
            }
            stockEntity.setLockStatus(activeNew);
            stockEntity.setUpdater(userId);
            stockEntity.setUpdateDate(new Date());
            stockMapper.updateById(stockEntity);
        }
    }

    @Override
    @WmsLogs(name = "原材直发出库")
    @Transactional(rollbackFor = Exception.class)
    public void directOut(BatchForbidRequestDTO request) {
        List<Long> stockIds = request.getIds(); // 获取前端传递的 ID 集合
        if (stockIds == null || stockIds.isEmpty()) {
            throw new ServiceException("未选择出库库存");
        }
        Long userId = request.getUserId();
        String msg = "";
        String comment = "原材直发出库";
        Date startDate = new Date();
        for (Long stockId : stockIds) {
            //生成盘库任务 proc_wms_stock_check
            StockEntity stockEntity = stockMapper.selectById(stockId);
            if (ObjectUtils.isEmpty(stockEntity)) {
                msg = "库存[" + stockId + "]在表中不存在!请核查";
                throw new ServiceException(msg);
            }
            //只有[初始]状态的库存允许出库
            String contNo = stockEntity.getContNo();
            if (stockEntity.getStockStatus() != 0 || stockEntity.getLockStatus() != 0) {
                msg = "托盘[" + contNo + "]的库存状态不允许盘点";
                throw new ServiceException(msg);
            }
            //只有在实际货位上的库存，才允许库存盘点
            QueryWrapper<LocationEntity> locationWrapper = new QueryWrapper<>();
            locationWrapper.eq("location_no", stockEntity.getLocationNo());
            LocationEntity locationEntity = locationMapper.selectOne(locationWrapper);
            if (!"1".equals(locationEntity.getLocationType())) {
                msg = "托盘[" + contNo + "]当前所在位置[" + stockEntity.getLocationNo() + "]不允许盘点";
                throw new ServiceException(msg);
            }
            StockEntity updateStock = new StockEntity();
            updateStock.setStockStatus(1);
            updateStock.setStockId(stockId);
            updateStock.setComments(comment);
            updateStock.setUpdater(userId);
            updateStock.setUpdateDate(startDate);
            try {
                stockMapper.updateById(updateStock);
            } catch (Exception e) {
                msg = "托盘[" + contNo + "]的库存修改失败";
                throw new ServiceException(msg);
            }
            //根据物料的区域 id获取出库站台
            SpuEntity spuEntity = spuMapper.selectOne(new QueryWrapper<SpuEntity>().eq("spu_no", stockEntity.getSpuNo()));
            //查询站台
            List<StationEntity> stationEntities = stationMapper.selectList(new QueryWrapper<StationEntity>()
                    .eq("zone_id", spuEntity.getZoneId())
                    .eq("station_type", WmsStationType.SOT.getCode())
                    .eq("is_active", UserStatus.OK.getCode()));
            if (CollectionUtils.isEmpty(stationEntities)) {
                msg = "当前无可用出库站台!";
                throw new ServiceException(msg);
            }
            StationEntity stationEntity = stationEntities.get(0);

            //业务任务 proc_wms_task_inser
            TaskEntity insertTask = new TaskEntity();
            insertTask.setTaskType(WmsTaskType.SHIPMENT_OUT.getCode());
            insertTask.setTaskSubType(WmsTaskSubType.DELIVERY_OUT.getCode());
            insertTask.setFromContNo(contNo);
            insertTask.setSpuNo(stockEntity.getSpuNo());
            insertTask.setPlanQty(stockEntity.getStockQty());
            insertTask.setActualQty(BigDecimal.ZERO);
            insertTask.setFromPosition(stockEntity.getLocationNo());
            insertTask.setCurPosition(stockEntity.getLocationNo());
            insertTask.setToPosition(stationEntity.getStationNo());
            insertTask.setStockId(stockId);
            insertTask.setTaskStatus(WmsTaskStatus.PROGRESS.getCode());
            insertTask.setCreator(userId);
            insertTask.setCreateDate(startDate);
            insertTask.setUpdater(userId);
            insertTask.setUpdateDate(startDate);
            insertTask.setComments(comment);
            try {
                taskMapper.insert(insertTask);
            } catch (ServiceException e) {
                msg = "托盘[" + contNo + "]的库存修改失败";
                throw new ServiceException(msg);
            }

            WarehouseEntity warehouseEntity = warehouseMapper.selectById(insertTask.getWarehouseId());
            //如果是自动库，就下发设备任务
            if (warehouseEntity.getWarehouseType().equals(WmsWarehouseType.AUTOMATED.getCode())) {
                //生成设备任务
                WcsTaskEntity insertPostWcs = new WcsTaskEntity();
                insertPostWcs.setContNo(insertTask.getFromContNo());
                insertPostWcs.setTrkType(WmsTaskType.SHIPMENT_OUT.getCode());
                insertPostWcs.setFrmPos(insertTask.getFromPosition());
                insertPostWcs.setToPos(stationEntity.getStationNo());
                insertPostWcs.setCurPos(insertTask.getCurPosition());
                insertPostWcs.setTrkStatus(WmsTaskStatus.INITIAL.getCode());
                insertPostWcs.setCreator(userId);
                insertPostWcs.setCreateDate(startDate);
                insertPostWcs.setUpdater(userId);
                insertPostWcs.setUpdateDate(startDate);
                insertPostWcs.setComments(comment);
                try {
                    wcsTaskMapper.insert(insertPostWcs);
                } catch (Exception e) {
                    msg = "生成设备任务失败!任务[" + insertTask.getTaskId() + "]!";
                    throw new ServiceException(msg);
                }
            }
        }
    }

    @Override
    @WmsLogs(name = "出库领料确认")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult outAffirm(TaskRequestDTO request) {
        String contNo = request.getContNo();
        Integer actlQty = request.getActlQty();
        Long taskId = request.getTaskId();
        TaskEntity taskEntity = taskMapper.selectById(taskId);
        if (ObjectUtils.isEmpty(taskEntity) || WmsTaskStatus.PROGRESS.getCode() != taskEntity.getTaskStatus()) {
            throw new ServiceException("没有正在执行的托盘任务");
        }
        if (actlQty != taskEntity.getPlanQty().intValue()) {
            throw new ServiceException("领料数量必须等于计划数量！");
        }
        if (!contNo.equals(taskEntity.getFromContNo())) {
            throw new ServiceException("当前托盘号与任务托盘号不一致！");
        }
        if (!taskEntity.getSpuNo().equals(request.getSpuNo())) {
            throw new ServiceException("领取物料和任务物料不一致！");
        }
        Date startDate = new Date();
        String code = "0";
        String msg = "出库确认";
        String comment = "出库确认";
        String work = "RfController.outboundCompleted";
        Long userId = request.getUserId();
        try {
            taskMapper.update(null, new UpdateWrapper<TaskEntity>().eq("task_id", taskId)
                    .set("actual_qty", new BigDecimal(actlQty))
                    .set("task_status", WmsTaskStatus.COMPLETE.getCode())
                    .set("updater", userId).set("update_date", startDate));
        } catch (Exception e) {
            log.info("修改任务失败", e);
            throw new ServiceException("修改任务失败！");
        }
        Long stockId = taskEntity.getStockId();
        StockEntity stockEntity = stockMapper.selectById(stockId);
        BigDecimal stockQty = stockEntity.getStockQty().subtract(new BigDecimal(actlQty));
        BigDecimal lockedQty = stockEntity.getLockedQty().subtract(new BigDecimal(actlQty));
        if (BigDecimal.ZERO.compareTo(stockQty) > 0) {
            throw new ServiceException("库存不足！");
        }
        try {
            if (BigDecimal.ZERO.compareTo(stockQty) == 0) {
                stockMapper.deleteById(stockId);
            } else {
                stockMapper.update(null, new UpdateWrapper<StockEntity>().eq("stock_id", stockId)
                        .set("stock_qty", stockQty).set("locked_qty", lockedQty)
                        .set("updater", userId).set("update_date", startDate));
            }
        } catch (Exception e) {
            log.info("修改库存失败", e);
            throw new ServiceException("修改库存失败！");
        }
        //订单状态
        List<Integer> taskStList = new ArrayList<>();
        taskStList.add(WmsTaskStatus.PROGRESS.getCode());
        taskStList.add(WmsTaskStatus.INITIAL.getCode());
        List<TaskEntity> list = taskMapper.selectList(new QueryWrapper<TaskEntity>()
                .eq("detail_id", taskEntity.getDetailId()).in("task_status", taskStList));
        if (CollectionUtils.isEmpty(list)) {
            ObDetailEntity updateOrderDetail = obDetailMapper.selectById(taskEntity.getDetailId());
            //出库实际需要累加
            BigDecimal curActlQty = updateOrderDetail.getObActualQty().add(new BigDecimal(actlQty));
            updateOrderDetail.setObActualQty(curActlQty);
            updateOrderDetail.setObDetailStatus(WmsBusinessStatus.OB_DETAIL_DONE.getCode());
            updateOrderDetail.setUpdater(userId);
            updateOrderDetail.setUpdateDate(startDate);
            updateOrderDetail.setComments(comment);
            try {
                obDetailMapper.updateById(updateOrderDetail);
            } catch (Exception e) {
                log.info("修改出库明细失败", e);
                throw new ServiceException("修改出库明细失败！");
            }
            //修改主单状态
            Map<String, Object> params = new HashMap<>();
            params.put("orderId", updateOrderDetail.getObMasterId());
            params.put("comment", comment);
            params.put("userId", userId);
            // TODO 更新单据状态
        }
        List<TaskEntity> taskEntityList = taskMapper.selectList(new QueryWrapper<TaskEntity>().lambda().eq(TaskEntity::getFromContNo, contNo).eq(TaskEntity::getTaskStatus, WmsTaskStatus.PROGRESS.getCode()));
        if (!CollectionUtils.isEmpty(taskEntityList)) {
            return AjaxResult.success("物料并未领完，请继续领料！");
        }
        List<StockEntity> stockEntities = stockMapper.selectList(new QueryWrapper<StockEntity>().eq("cont_no", contNo));
        if (CollectionUtils.isEmpty(stockEntities)) {
            return AjaxResult.success("托盘物料已领完，请执行空托盘入库！");
        }
        ContainerEntity containerEntity = contMapper.selectOne(new QueryWrapper<ContainerEntity>().eq("cont_no", contNo));
        List<LocationEntity> locateEntities;

        LocationEntity locationEntity = locationService.selectToLocationByZoneId(containerEntity.getZoneId());
        if (ObjectUtils.isEmpty(locationEntity)) {
            throw new ServiceException("没有空闲的货位！");
        }
        //货位预分配
        UpdateWrapper<LocationEntity> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(LocationEntity::getLocationId, locationEntity.getLocationId())
                .eq(LocationEntity::getLocationStatus, WmsLocateStatus.FREE.getCode())
                .set(LocationEntity::getLocationStatus, WmsLocateStatus.PRE.getCode())
                .set(LocationEntity::getContNo, contNo)
                .set(LocationEntity::getComments, comment)
                .set(LocationEntity::getUpdater, userId)
                .set(LocationEntity::getUpdateDate, startDate);

        try {
            int locateUpdateNum = locationMapper.update(updateWrapper);
            if (locateUpdateNum <= 0) {
                throw new ServiceException("货位预占用失败！");
            }
        } catch (Exception e) {
            log.info("货位预占用失败，货位号={}", locationEntity.getLocationNo(), e);
            throw new ServiceException("货位预占用失败！");
        }

        //根据料箱获取出库站台信息
        String dvcNo = containerEntity.getContType();
        //查询站台
        List<StationEntity> stationEntities = stationMapper.selectList(new QueryWrapper<StationEntity>()
                .eq("dvc_no", dvcNo)
                .eq("station_type", WmsStationType.SOT.getCode())
                .eq("is_active", UserStatus.OK.getCode()));
        if (CollectionUtils.isEmpty(stationEntities)) {
            msg = "当前无可用出库站台!";
            throw new ServiceException(msg);
        }
        StationEntity stationEntity = stationEntities.get(0);
        String fromPosition = stationEntity.getStationNo();

        StockEntity stockEntity1 = stockEntities.get(0);
        TaskEntity insertTask = new TaskEntity();
        insertTask.setTaskType(WmsTaskType.RECEIVE_IN.getCode());
        insertTask.setTaskSubType(WmsTaskSubType.PICK_BACK.getCode());
        insertTask.setFromContNo(contNo);
        insertTask.setFromPosition(fromPosition);
        insertTask.setToPosition(locationEntity.getLocationNo());
        insertTask.setCurPosition(fromPosition);
        insertTask.setTaskStatus(WmsTaskStatus.INITIAL.getCode());
        insertTask.setCreateDate(startDate);
        insertTask.setCreator(userId);
        insertTask.setUpdater(userId);
        insertTask.setUpdateDate(startDate);
        insertTask.setComments(comment);
        insertTask.setSpuNo(stockEntity1.getSpuNo());
        insertTask.setPlanQty(stockEntity1.getStockQty());
        insertTask.setActualQty(stockEntity1.getStockQty());
        insertTask.setStockId(stockEntity1.getStockId());
        try {
            taskMapper.insert(insertTask);
        } catch (Exception e) {
            log.info("生成任务失败", e);
            throw new ServiceException("生成任务失败！");
        }
        //生成搬送任务
        WcsTaskEntity insertPostWcs = new WcsTaskEntity();
        insertPostWcs.setContNo(contNo);
        insertPostWcs.setContType(dvcNo);
        insertPostWcs.setTrkType(WmsTaskType.RECEIVE_IN.getCode());
        //起始位置与wms_task保持一致
        insertPostWcs.setFrmPos(fromPosition);
        insertPostWcs.setToPos(locationEntity.getLocationNo());
        insertPostWcs.setCurPos(fromPosition);
        insertPostWcs.setTrkStatus(WmsTaskStatus.INITIAL.getCode());
        insertPostWcs.setCreator(userId);
        insertPostWcs.setCreateDate(startDate);
        insertPostWcs.setUpdater(userId);
        insertPostWcs.setUpdateDate(startDate);
        insertPostWcs.setComments(comment);
        try {
            wcsTaskMapper.insert(insertPostWcs);
        } catch (Exception e) {
            log.info("生成搬送任务失败", e);
            throw new ServiceException("生成搬送任务失败！");
        }
        msg = "从容器[" + contNo + "]中领取器材[" + request.getSpuNo() + "]数量[" + actlQty + "]成功!";
        return AjaxResult.success(msg);
    }
}
